From 942c2f964d2d3a2c403ace599bbaafb4b5b8247c Mon Sep 17 00:00:00 2001 From: "shand@kneesaa.uk.xensource.com" Date: Wed, 16 Aug 2006 14:01:03 +0100 Subject: [PATCH] Heuristic to detect windows shutdown + power down domain. Signed-off-by: Steven Hand Signed-off-by: George Dunlap --- xen/arch/x86/hvm/svm/svm.c | 22 ++++++++++++++++++++-- xen/arch/x86/hvm/vmx/vmx.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 9f46235463..e971f272e5 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -2150,8 +2150,9 @@ done: static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb) { struct vcpu *v = current; - struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm; - s_time_t next_pit = -1, next_wakeup; + struct periodic_time *pt = + &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + s_time_t next_pit = -1, next_wakeup; __update_guest_eip(vmcb, 1); @@ -2159,6 +2160,23 @@ static inline void svm_vmexit_do_hlt(struct vmcb_struct *vmcb) if ( vmcb->vintr.fields.irq || cpu_has_pending_irq(v) ) return; + /* Detect machine shutdown. Only do this for vcpu 0, to avoid + potentially shutting down the domain early. */ + if (v->vcpu_id == 0) { + unsigned long rflags = vmcb->rflags; + /* If we halt with interrupts disabled, that's a pretty sure + sign that we want to shut down. In a real processor, NMIs + are the only way to break out of this. Our SVM code won't + deliver interrupts, but will wake it up whenever one is + pending... */ + if(!(rflags & X86_EFLAGS_IF)) { + printk("D%d: HLT with interrupts enabled @0x%lx Shutting down.\n", + current->domain->domain_id, (unsigned long)vmcb->rip); + domain_shutdown(current->domain, SHUTDOWN_poweroff); + return; + } + } + if ( !v->vcpu_id ) next_pit = get_scheduled(v, pt->irq, pt); next_wakeup = get_apictime_scheduled(v); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index ef84d539ac..ea52efdb33 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2054,9 +2054,32 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs) */ void vmx_vmexit_do_hlt(void) { - struct vcpu *v=current; - struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm); - s_time_t next_pit=-1,next_wakeup; + struct vcpu *v = current; + struct periodic_time *pt = + &(v->domain->arch.hvm_domain.pl_time.periodic_tm); + s_time_t next_pit = -1, next_wakeup; + + + /* Detect machine shutdown. Only do this for vcpu 0, to avoid + potentially shutting down the domain early. */ + if (v->vcpu_id == 0) { + unsigned long rflags; + + __vmread(GUEST_RFLAGS, &rflags); + /* If we halt with interrupts disabled, that's a pretty sure + sign that we want to shut down. In a real processor, NMIs + are the only way to break out of this. Our VMX code won't + deliver interrupts, but will wake it up whenever one is + pending... */ + if(!(rflags & X86_EFLAGS_IF)) { + unsigned long rip; + __vmread(GUEST_RIP, &rip); + printk("D%d: HLT with interrupts enabled @0x%lx Shutting down.\n", + current->domain->domain_id, rip); + domain_shutdown(current->domain, SHUTDOWN_poweroff); + return; + } + } if ( !v->vcpu_id ) next_pit = get_scheduled(v, pt->irq, pt); -- 2.30.2